
#pragma once

#include <stdint.h>
#include <stdlib.h>


#define MD5_DIGEST_SIZE 16
#define MD5_BLOCK_SIZE 64
/* For backwards compatibility */
#define MD5_DATA_SIZE MD5_BLOCK_SIZE

/* Digest is kept internally as 4 32-bit words. */
#define _MD5_DIGEST_LENGTH 4

/** A hasher class for md5. */
class CMD5
{
private:
    struct md5_ctx
    {
        uint32_t state[_MD5_DIGEST_LENGTH];
        uint64_t count;               /* Block count */
        uint8_t block[MD5_BLOCK_SIZE]; /* Block buffer */
        unsigned index;               /* Into buffer */
    } ctx_;

    void MD5_Init();
    void MD5_Update(size_t length,const uint8_t *data);
    void MD5_Final(uint8_t *digest);
    void _nettle_md5_compress(uint32_t *digest, const uint8_t *input);
public:
    static const size_t OUTPUT_SIZE         = 16;
    static const size_t BLOCK_SIZE          = 64;
    static const size_t OUTPUT_HMAC_SIZE    = 16;

    CMD5() {
        MD5_Init();
    }

    CMD5& Write(const unsigned char* data, size_t len) {
        MD5_Update(len, (uint8_t*)data);
        return *this;
    }

    void Finalize(unsigned char hash[MD5_DIGEST_SIZE]) {
        MD5_Final((uint8_t*)hash);
    }

    CMD5& Reset() {
        MD5_Init();
        return *this;
    }
};